using System;
using System.Globalization;
using System.Text;
using EnvDTE;

namespace ConvertSourceToHtml.Conversion.HtmlCodeElements
{

    /// <summary>
    /// Represents a style in an HTML stylesheet based on a <see cref="ColorableItems"/> object 
    /// from Visual Studio and an optional parent style.
    /// </summary>
    /// <remarks>
    /// <para>
    /// <see cref="ColorableItemStyle"/> supports XML serialization so that instances can be
    /// serialized, deserialized, and fed into <see cref="Copier"/> for regression testing.
    /// </para>
    /// </remarks>
    public sealed class ColorableItemStyle : HtmlStyle
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorableItemStyle"/> class with the 
        /// specified <see cref="ColorableItems"/> object.
        /// </summary>
        /// <param name="colorItem">The <see cref="ColorableItems"/> object.</param>
        public ColorableItemStyle(ColorableItems colorItem)
			: this(HtmlColor.ConvertOleColor(colorItem.Foreground), HtmlColor.ConvertOleColor(colorItem.Background), colorItem.Bold, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorableItemStyle"/> class with the 
        /// specified <see cref="ColorableItems"/> object and parent style.
        /// </summary>
        /// <param name="colorItem">The <see cref="ColorableItems"/> object.</param>
        /// <param name="parentStyle">The parent style, or <see langword="null"/> if the style 
        /// doesn't have a parent style.</param>
        public ColorableItemStyle(ColorableItems colorItem, ColorableItemStyle parentStyle)
			: this(HtmlColor.ConvertOleColor(colorItem.Foreground), HtmlColor.ConvertOleColor(colorItem.Background), colorItem.Bold, parentStyle)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorableItemStyle"/> class with the 
        /// specified foreground color, background color, and bold value, without a parent style.
        /// </summary>
        /// <param name="foregroundColor">The foreground color.</param>
        /// <param name="backgroundColor">The background color.</param>
        /// <param name="bold"><see langword="true"/> if the style is bold, <see langword="false"/>
        /// otherwise.</param>
        public ColorableItemStyle(HtmlColor foregroundColor, HtmlColor backgroundColor, bool bold)
            : this(foregroundColor, backgroundColor, bold, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorableItemStyle"/> class with the 
        /// specified foreground color, background color, bold value, and parent style.
        /// </summary>
        /// <param name="foregroundColor">The foreground color.</param>
        /// <param name="backgroundColor">The background color.</param>
        /// <param name="bold"><see langword="true"/> if the style is bold, <see langword="false"/>
        /// otherwise.</param>
        /// <param name="parentStyle">The parent style, or <see langword="null"/> if the style 
        /// doesn't have a parent style.</param>
        public ColorableItemStyle(HtmlColor foregroundColor, HtmlColor backgroundColor, bool bold, ColorableItemStyle parentStyle)
        {
            Safety.AssertArgumentNotNull("foregroundColor", foregroundColor);
            Safety.AssertArgumentNotNull("backgroundColor", backgroundColor);
            // parentStyle can be null.

            ForegroundColor = foregroundColor;
            BackgroundColor = backgroundColor;
            Bold = bold;
            ParentStyle = parentStyle;
        }

        /// <summary>
        /// Private constructor required for XML serialization.
        /// </summary>
        private ColorableItemStyle()
        {
        }

        #endregion // Constructors

        #region Properties

        /// <summary>
        /// Gets or sets the foreground color.
        /// </summary>
        public HtmlColor ForegroundColor { get; set; }

        /// <summary>
        /// Gets or sets the background color.
        /// </summary>
		public HtmlColor BackgroundColor { get; set; }

        /// <summary>
        /// Gets or sets whether the style is bold or not.
        /// </summary>
        public bool Bold { get; set; }

        /// <summary>
        /// Gets or sets the parent <see cref="ColorableItemStyle"/>.
        /// </summary>
        public ColorableItemStyle ParentStyle { get; set; }

        /// <summary>
        /// Gets the length of the style.
        /// </summary>
        /// <value>The length of the style.</value>
        public override int Length
        {
            get { return ToString().Length; }
        }
        #endregion // Properties

        #region Methods

        /// <summary>
        /// Returns the string representation of the style.
        /// </summary>
        /// <returns>A string representation of the style.</returns>
        public override string ToString()
        {
            StringBuilder result;

            result = new StringBuilder();

            if ((ParentStyle == null) || (!ForegroundColor.Equals(ParentStyle.ForegroundColor)))
            {
                result.AppendFormat("color: {0}; ", ForegroundColor);
            }
            
            if ((ParentStyle == null) || (!BackgroundColor.Equals(ParentStyle.BackgroundColor)))
            {
                result.AppendFormat("background: {0}; ", BackgroundColor);
            }
            
            if ((ParentStyle == null) && Bold)
            {
                result.Append("font-weight: bold; ");
            }
            else if ((ParentStyle != null) && (Bold != ParentStyle.Bold))
            {
                if (Bold)
                {
                    result.Append("font-weight: bold; ");
                }
                else
                {
                    result.Append("font-weight: normal; ");
                }
            }
            
            result.Append(base.ToString());
            
            return result.ToString().Trim();
        }

		#endregion // Methods
    }

}
